// Copyright (c) 2011 Blue Onion Software, All rights reserved
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Xml.Serialization;

namespace BlueOnionSoftware.Bloget
{
    public class Post
    {
        private string _title;
        private string _author;
        private bool _draft;
        private readonly List<int> _tags = new List<int>();

        public Post()
        {
            Created = DateTime.UtcNow;
            EnableComments = true;
            Syndicate = true;
            Id = Guid.NewGuid();
        }

        internal Post(Post post)
        {
            Created = DateTime.UtcNow;
            EnableComments = true;
            Syndicate = true;
            Id = Guid.NewGuid();
            if (post == null)
            {
                throw new ArgumentNullException("post");
            }
            Id = post.Id;
            _title = post._title;
            _author = post._author;
            _draft = post._draft;
            Syndicate = post.Syndicate;
            EnableComments = post.EnableComments;
            Created = post.Created;
            if (post._tags != null)
            {
                _tags.AddRange(post._tags);
            }
        }

        [XmlElement("id")]
        public Guid Id { get; set; }

        [XmlElement("title")]
        public string Title
        {
            get { return _title ?? string.Empty; }
            set { _title = value; }
        }

        [XmlElement("author")]
        public string Author
        {
            get { return _author ?? string.Empty; }
            set { _author = value; }
        }

        [XmlElement("draft")]
        public bool Draft
        {
            get { return _draft; }

            set
            {
                if (_draft != value)
                {
                    Created = DateTime.UtcNow;
                    _draft = value;
                }
            }
        }

        [XmlElement("syndicate")]
        public bool Syndicate { get; set; }

        [XmlElement("comments")]
        public bool EnableComments { get; set; }

        [XmlElement("created")]
        public DateTime Created { get; set; }

        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays"), XmlArray("tags")]
        [XmlArrayItem("tag", typeof (int))]
        public int[] Tags
        {
            get { return _tags.ToArray(); }

            set
            {
                _tags.Clear();

                if (value != null)
                {
                    _tags.AddRange(value);
                }
            }
        }

        internal bool HasCategory(Category category)
        {
            return (category != null) ? _tags.Contains(category.Id) : false;
        }

        internal void AddCategory(Category category)
        {
            if (category == null)
            {
                throw new ArgumentNullException("category");
            }
            if (HasCategory(category) == false)
            {
                _tags.Add(category.Id);
            }
        }

        internal void RemoveCategory(Category category)
        {
            if (category == null)
            {
                throw new ArgumentNullException("category");
            }
            var index = _tags.IndexOf(category.Id);

            if (index != -1)
            {
                _tags.Remove(category.Id);
            }
        }

        internal void ClearCategories()
        {
            _tags.Clear();
        }

        public override string ToString()
        {
            return Title ?? "null title";
        }
    }

    public class PostCollection : KeyedCollection<Guid, Post>
    {
        public PostCollection()
        {
        }

        internal PostCollection(IEnumerable<Post> postCollection)
        {
            if (postCollection == null)
            {
                throw new ArgumentException("postCollection");
            }

            foreach (var post in postCollection)
            {
                Add(new Post(post));
            }
        }

        protected override Guid GetKeyForItem(Post item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }
            return item.Id;
        }

        internal Post Previous(Guid id)
        {
            if (Contains(id))
            {
                var i = IndexOf(this[id]);
                while (--i >= 0)
                {
                    if (this[i].Draft == false)
                    {
                        return this[i];
                    }
                }
            }

            return null;
        }

        internal Post Next(Guid id)
        {
            if (Contains(id))
            {
                var i = IndexOf(this[id]);

                while (++i < Count)
                {
                    if (this[i].Draft == false)
                    {
                        return this[i];
                    }
                }
            }

            return null;
        }

        internal void InsertByDate(Post post)
        {
            if (post == null)
            {
                throw new ArgumentNullException("post");
            }
            // Assumes the blog is already sorted.
            for (var i = 0; i < Count; ++i)
            {
                if (post.Created > this[i].Created)
                {
                    Insert(i, post);
                    return;
                }
            }

            Add(post);
        }
    }
}